/*
 * Copyright (c) 2009 John Pritchard, WTKX Project Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package wtkx.ui;

import wtkx.Component;
import wtkx.io.CC;
import wtkx.io.CSS;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.Shape;

/**
 * Syntax 
 * <pre>
 * width
 * color
 * width style
 * width color
 * width style color
 * </pre>
 * 
 * for width a plain (base ten) number of pixels (never a trailing
 * 'px' or 'pt' or '%').
 *
 * @author jdp
 */
public class Border 
    extends Object
    implements jbxml.Value
{
    protected final static Border DefaultDebug = new Border(0.5f,Style.Solid,Color.red);

    public enum Style {
        None("none"),
        Hidden("hidden"),
        Dotted("dotted"),
        Dashed("dashed"),
        Solid("solid"),
        Double("double"),
        DotDash("dot-dash"),
        DotDotDash("dot-dot-dash"),
        Wave("wave"),
        Groove("groove"),
        Ridge("ridge"),
        Inset("inset"),
        Outset("outset");


        public final String id;

        private Style(String id){
            this.id = id;
        }

        public String toString(){
            return this.id;
        }

        public final static Style decode(String value){
            return valueOf(CSS.ClassCamel(value));
        }
    }


    public float width;

    public Style style;

    public Color color;

    protected Border debug, focused;

    protected boolean infocus;


    public Border() {
        super();
        this.style = Style.None;
    }
    public Border(float w){
        super();
        this.width = w;
        this.style = Style.Solid;
    }
    public Border(float w, Style style, Color color){
        super();
        this.width = w;
        this.style = style;
        this.color = color;
    }
    public Border(String css) {
        super();
        this.fromString(css);
    }
    public Border(Border b, float w){
        super();
        this.width = w;
        this.style = b.style;
        this.color = b.color;
    }


    public boolean isEmpty(){
        return (0 == this.width && Style.None == this.style);
    }
    public boolean isNotEmpty(){
        return (0 != this.width && Style.None != this.style);
    }
    public void hidden(){
        this.style = Style.Hidden;
    }
    public boolean isHidden(){
        return (Style.Hidden == this.style);
    }
    public void none(){
        this.style = Style.None;
    }
    public boolean isNone(){
        return (Style.None == this.style);
    }
    public Border getDebug(){
        return this.debug;
    }
    public void setDebug(Border debug){
        this.debug = debug;
    }
    public void setDebug(){
        if (null == this.debug)
            this.debug = Border.DefaultDebug;
        else
            this.debug = null;
    }
    public void clearDebug(){
        this.debug = null;
    }
    public Border getFocused(){
        return this.focused;
    }
    public void setFocused(Border b){
        this.focused = b;
    }
    public void focusChanged(boolean b){
        if (null != this.debug)
            this.debug.focusChanged(b);

        this.infocus = b;
    }
    public void fill(Component c, Graphics2D g){

        this.fill(c,g, c.getBorderOutline());
    }
    public void fill(Component c, Graphics2D g, Shape shape){

        if (null != this.debug)
            this.debug.fill(c,g,shape);
        else {
            Style style = this.style;
            if (Style.Hidden == style)
                return;
            else {
                Color bg = c.getBackgroundColor();
                if (null != bg){
                    g.setColor(bg);

                    if (null != shape){
                        g.fill(shape);
                    }
                }
                this.draw(c,g,shape);
            }
        }
    }
    public void draw(Component c, Graphics2D g){

        this.draw(c,g, c.getBorderOutline());
    }
    public void draw(Component c, Graphics2D g, Shape shape){

        if (this.infocus){
            Border focused = this.focused;
            if (null != focused){
                this.focused.draw(c,g,shape);
                return;
            }
        }

        float border = this.width;
        if (0 < border){
            Style style = this.style;
            if (Style.None == style || Style.Hidden == style)
                return;
            else {
                Color color = this.color;
                if (null == color){
                    color = c.getColor();
                    if (null == color)
                        return;
                }
                if (null != shape){
                    Stroke stroke = null;

                    if (Style.Solid == this.style){
                        stroke = new BasicStroke(border);
                    }
                    /*
                     * TODO (dashed and dotted are easy)
                     */

                    if (null != stroke){
                        g.setColor(color);
                        g.setStroke(stroke);
                        g.draw(shape);
                    }
                }
            }
        }
    }
    public float getWidth(){
        return this.width;
    }
    public void setWidth(float w){
        if (0 < w)
            this.width = w;
    }
    public Style getStyle(){
        return this.style;
    }
    public void setStyle(Style style){
        if (null != style)
            this.style = style;
    }
    public void setStyle(String style){

        this.setStyle(Style.decode(style));
    }
    public Color getColor(){
        return this.color;
    }
    public void setColor(Color color){
        if (null != color)
            this.color = color;
    }
    public void setColor(String string){
        this.setColor(CC.Decode(string));
    }
    public void fromString(String css){
        this.width = 0;
        this.style = Style.None;
        this.color = null;
        if (null != css){
            java.util.StringTokenizer strtok = new java.util.StringTokenizer(css," -\t\r\n");
            switch (strtok.countTokens()){
            case 0:
                this.width = 0;
                this.style = Style.None;
                this.color = null;
                break;
            case 1:
                String a = strtok.nextToken();
                try {
                    this.width = Float.parseFloat(a);
                    this.style = Style.Solid;
                    this.color = null;
                }
                catch (RuntimeException exc){
                    this.width = 1;
                    try {
                        this.style = Style.decode(a);
                        this.color = null;
                    }
                    catch (RuntimeException exc2){
                        this.style = Style.Solid;
                        this.color = CC.Decode(a);
                    }
                }
                break;
            case 2:
                this.width = Float.parseFloat(strtok.nextToken());
                String b = strtok.nextToken();
                try {
                    Color color = CC.Decode(b);
                    this.color = color;
                    this.style = Style.Solid;
                }
                catch (RuntimeException exc){
                    this.style = Style.decode(b);
                    this.color = null;
                }
                break;
            case 3:
                this.width = Float.parseFloat(strtok.nextToken());
                this.style = Style.decode(strtok.nextToken());
                this.color = CC.Decode(strtok.nextToken());
                break;
            default:
                throw new IllegalArgumentException(css);
            }
        }
    }
    public String toString(){
        StringBuilder string = new StringBuilder();
        string.append(this.width);
        string.append(' ');
        string.append(this.style);
        string.append(' ');
        Color color = this.color;
        if (null != color)
            string.append(CC.Encode(color));

        return string.toString();
    }
}
